package cacheobj

// 一个CacheKey对应一个CacheObject.
// 一个CacheObject可能对应多个Document(Vary场景), 但在大多数场景中仅有一个Document(99%场景下, 非Vary场景)
// 因此在我们设计中CacheObject最多包含一个Document, 用于减少IO次数, 提高性能, 这在小文件场景中是非常有必要的.
// 一个缓存副本包含一个Document和n个Fragment.

// CacheObject 缓存对象
// Key: 用于比对CacheKey
// VaryHeader: 源站最后一次Response的Vary Header, 我们仅以最后一次为准.
// - 某些客户的源站可能返回不同的Vary Header, 这是一种不规范的行为, 我们需兼容这种非预期的行为.
// VaryList: ZCACHE已经知道源站响应过哪些类型的副本列表, 可用于内容协商.
// UnsuitedVary: 不匹配的资源副本
// - 比如Vary是Accept-Encoding, 请求携带了Accept-Encoding: br, 但是源站响应的确实Content-Encoding: gzip.
// 为避免缓存功能失效, 我们这里会保存`UnsuitedVary[br] = gzip`, 从而避免副本协商失败导致的无法命中缓存问题.
// 通常情况下, 只要有已知的缓存资源, 即使资源部匹配, 我们也会选择该资源响应给客户, 除非客户显示关闭该功能.
type CacheObject struct {
	Key          []byte            // CacheKey
	VaryHeader   []byte            // 最后一次Response的Vary Header
	VaryList     [][]byte          // 源站响应了哪些Vary对象
	UnsuitedVary map[string]string // 不匹配的Vary列表
	Doc          *Document
}

// Document Document中包含了0-(512K-1)的Body内容.
type Document struct {
	Key           []byte              // DocKey, CacheKey + "|" + "VaryKey"
	ReqTime       int64               // 请求源站的Unix时间
	RespTime      int64               // 源站响应的Unix时间
	RespCode      int64               // 源站响应的状态码
	ContentLength int64               // 源站响应的内容长度
	RespHeader    map[string][]string // 响应头
	Body          []byte
}

// Fragment 不包含异常状态码缓存
// 如果请求从Document中拿到2xx状态码, 之后获取Fragment时出现异常状态码, 那么本次请求将中断.
// 默认情况下, Fragment状态码异常不会删除Document(这意味着源站异常, 但是资源未过期).
// 在客户源站出现异常, Document被缓存情况下, 而获取到不符合预期的Fragment而长时间出现请求中断, 而非异常状态码响应.
// 如果用户期望收到异常状态码响应, 而非请求问题时, 可选择开启相关配置, 在此场景下删除对应的Document.
type Fragment struct {
	Key        []byte // Fragment, CacheKey + "|" + "VaryKey" + "|" + "range=n-m"
	RespHeader map[string][]string
	Body       []byte
}
